#ifndef	_XDCACHE_H_
#define	_XDCACHE_H_

		/*
		 * Simulator's data access cache model
		 * Overloaded to simulate datacaches, and TLB accesses etc.
		 * Basically - fast tracks as many loads/stores as possible,
		 * then misses to handle exceptional cases.
		 */

#define	XDCACHE_LINE_SIZE_BITS	13	/* 8K pages unless we want a real d-cache */
#define	XDCACHE_LINE_SIZE	(1<<XDCACHE_LINE_SIZE_BITS)
#define	XDCACHE_LINE_OFFSET_MASK	(XDCACHE_LINE_SIZE-1)
#define	XDCACHE_TAG_MASK	(~XDCACHE_LINE_OFFSET_MASK)

#define	XDCACHE_NUM_LINES_BITS	7	/* 128 entries (must be at least 4, as we need 2 bits in tag) */
#define	XDCACHE_NUM_LINES	(1<<XDCACHE_NUM_LINES_BITS)	/* 64 entries */


#if (XDCACHE_LINE_SIZE_BITS+XDCACHE_NUM_LINES_BITS)>=32
#error	Total number of bits spanned by XDcache must be less than 32 for SPARC address masking to work
#endif


		/*
		 * The tag match algorithm is design to test 3 things simultaneously:
		 * Tag match + alignment + access permission.
		 *
		 * We need 2 bits for access permission and validity checks in the tag field.
		 * We also reserve 3 bits to test the correct access alignment.
		 * Thus the tag field holds a maximum of 64-2-3 = 58 bits of the tag.
		 * These become fewer if the cache lines are larger than 32 bytes.
		 *
		 * So, suppose there is a 4 byte read to address 0x3ce000.
		 *
		 * A matching tag would look something like 0x3ce008.
		 *
		 * The check looks something like: (addr | READ_PERM) ^ tag
		 * If the read perm bit is not set in the tag, then tag bit field in the result is non-zero.
		 * If addr is not aligned correctly, then the bottom 2 bits are non zero.
		 * If the tag doesn't match then the upper bits are non-zero.
		 * So to check for a match, mask the result with a mask with the upper bits set
		 * (for the actual tag fields), the READ_PERM bit, and the bottom N (2) bits set for
		 * checking alignment.
		 * This mask is concocted appropriately for each type of load.
		 *
		 * Thus trivially, a suitable invalid tag is one where neither the READ_PERM nor WRITE_PERM bits
		 * are set .. i.e. 0.
		 */

typedef struct {
	tvaddr_t	tag;
#define	XDCACHE_INVALID_TAG	0
#define	XDCACHE_READ_PERM	0x8
#define	XDCACHE_WRITE_PERM	0x10
	uint64_t	offset;	/* addr + offset = location of data in simulator memory */
} xdcache_line_t;

	/*
	 * Try to optimize locating of xdc_line by using raw values to
	 * avoid excess shifts and masking by compiler
	 */

#define	XDCACHE_RAW_LINE_BITS	4	/* 16 bytes sizeof(tvaddr_t) + sizeof(offset) */
#define	XDCACHE_RAW_SHIFT	(XDCACHE_LINE_SIZE_BITS - XDCACHE_RAW_LINE_BITS)
#define	XDCACHE_RAW_LINE_MASK	((XDCACHE_NUM_LINES-1) << XDCACHE_RAW_LINE_BITS)


#define	XDCACHE_SANITY_CHECK()	do {						\
	ASSERT( XDCACHE_RAW_SHIFT >= 3 );	/* must ensure miss-align bits shift off */\
	ASSERT( sizeof(xdcache_line_t) == (1<<XDCACHE_RAW_LINE_BITS) );		\
	} while (0)

typedef struct {
	config_addr_t * miss_addrp;	/* cache of last memory miss address */
	void (*miss)(simcpu_t * sp, uint64_t * regp, tvaddr_t addr, int op);
	xdcache_line_t line[XDCACHE_NUM_LINES];
} xdcache_t;



extern void xdcache_flush(simcpu_t * sp);

#if PERFORMANCE_CHECK /* { */
#define	XDC_HIT(sp)     do { (sp)->xdc_hits++; } while (0)
#define	XDC_MISS(sp)    do { (sp)->xdc_misses++; } while (0)
#else
#define	XDC_HIT(sp)     do { } while (0)
#define	XDC_MISS(sp)    do { } while (0)
#endif	/* PERFORMANCE_CHECK } */

#endif	/* _XDCACHE_H_ */
